Skip to content

Conversation

catamorphism
Copy link
Contributor

At this point, there should be no further uses of the preview1 component adapter for clocks and filesystems methods when __wasilibc_use_wasip2 is defined.

Also added a DEBUG option to the Makefile that enables -O0/g when DEBUG=true is passed in.

@catamorphism
Copy link
Contributor Author

Note: there's no automated way (that I know of) to check that there are no uses of the preview1 filesystems methods when __wasilibc_use_wasip2 is defined, so I checked by searching for each of the method names and verifying that it was enclosed in an appropriate #ifdef. It's possible I could have missed something.

Copy link
Collaborator

@pchickey pchickey left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So far reviewed clocks, this one will take time to go through piece by piece

catamorphism and others added 5 commits August 15, 2025 13:08
At this point, there should be no further uses of the preview1
component adapter for clocks and filesystems methods when __wasilibc_use_wasip2
is defined.

Also added a DEBUG option to the Makefile that enables -O0/g
when DEBUG=true is passed in.
Copy link
Collaborator

@pchickey pchickey left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Today I made it up to the end of the libc itself, and I skimmed the tests. I'll give the tests another read-through later.

It appears __wasilibc_fd_renumber isnt ported in this PR - that should be possible to implement just by manipulating libc's own descriptor table

}

if (!dir_entry_optional.is_some) {
// End-of-file
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Need to close the stream and remove it from the descriptor table - otherwise its effectively leaked. (And in the error case as well)

fs_flags |= FILESYSTEM_DESCRIPTOR_FLAGS_READ;
}
if ((oflag & O_WRONLY) != 0) {
// Sync flags are not supported yet
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this a TODO, or an assertion about implementations? I think you'd want to take care of the presence or absence of O_SYNC and translating that to a descriptor flag below this switch

@@ -110,6 +111,11 @@ int ioctl(int fildes, int request, ...) {
return 0;
}
case FIONBIO: {
#ifdef __wasilibc_use_wasip2
// wasip2 doesn't support setting the non-blocking flag
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thats correct, and for files this doesn't matter, but if this was a socket, I think we'd want to emulate setting the nonblocking flag by switching the implementations of send/recv from blocking to nonblocking stream read/writes. But just googling around it seems like this particular ioctl has a checkered past so maybe it doesn't matter if we just say ENOTSUP? Genuinely not sure what the right thing is to do here.

@@ -61,14 +61,24 @@ int pselect(int nfds, fd_set *restrict readfds, fd_set *restrict writefds,

int poll_timeout;
if (timeout) {
#ifdef __wasilibc_use_wasip2
wall_clock_datetime_t timestamp;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we want to use the monotonic clock for timeouts instead of the wall clock, since its about measuring duration


#ifdef __wasilibc_use_wasip2
// Following the behavior of the preview1 component adapter,
// only write the first non-empty iov
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't have super strong feelings about this, but I'm fine with trying to write as much as possible here by iterating through the iovs instead of following the component adapter's behavior, which has surprised some users.

if ((flags & ~TIMER_ABSTIME) != 0)
return EINVAL;

// Prepare polling subscription.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess this is fine for this PR but I do see its rewritten properly in #608 so all good.

return -1;
}
}
return bytes_skipped;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should this be total_bytes_skipped?

offset_to_use = offset + entry->stream.offset;
break;
case SEEK_END: {
// Find the end of the stream (is there a better way to do this?)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For file streams, I think the efficient way to implement this is to get the filestat and use the len field.


// Get the output stream
filesystem_own_output_stream_t stream_owned;
ok = filesystem_method_descriptor_write_via_stream(entry->file.file_handle,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we cache a stream per file_handle to be used by write, rather than open a new one each write?


if (num_bytes_permitted < nbyte) {
streams_own_pollable_t pollable = streams_method_output_stream_subscribe(output_stream);
poll_method_pollable_block(poll_borrow_pollable(pollable));
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This pollable gets leaked - it needs a drop call. But also, can we cache it for next time this output stream is used? Creating a new pollable and dropping it each time creates more churn than ideal.

if (fildes == 1)
output_stream = streams_borrow_output_stream(stdout_get_stdout());
else if (fildes == 2)
output_stream = streams_borrow_output_stream(stderr_get_stderr());
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we cache these streams, as well, so that libc only needs to call get_stdout and get_stderr once for the lifetime of the instance?

// This is a tagged union. When adding/removing/renaming cases, be sure to keep the tag and union definitions in sync.
typedef struct {
enum {
DESCRIPTOR_TABLE_ENTRY_TCP_SOCKET,
DESCRIPTOR_TABLE_ENTRY_UDP_SOCKET,
DESCRIPTOR_TABLE_ENTRY_FILE_HANDLE,
DESCRIPTOR_TABLE_ENTRY_DIRECTORY_STREAM,
DESCRIPTOR_TABLE_ENTRY_FILE_STREAM
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mix of tabs/spaces

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants